using Abc.Core;
using Abc.Core.Entities;

using Furion;
using Furion.DatabaseAccessor;

using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Security.Claims;

using Tool;

namespace Abc.EntityFramework.Core
{
    //[AppDbContext("MySqlConnectionString")]
    //[AppDbContext("SqlServerConnectionString")]
    [AppDbContext("Sqlite3ConnectionString")]
    public class AbcDbContext : AppDbContext<AbcDbContext>, IModelBuilderFilter
    {
        public AbcDbContext(DbContextOptions<AbcDbContext> options) : base(options)
        {
            EnabledEntityChangedListener = true;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            // optionsBuilder.UseExceptionProcessor();
            base.OnConfiguring(optionsBuilder);
        }

        public DbSet<AutidLog> AutidLogs { get; set; }

        #region 全局筛选器

        public void OnCreated(ModelBuilder modelBuilder, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
            var expression = BuilderIsDeleteLambdaExpression(entityBuilder);
            if (expression == null) return;

            entityBuilder.HasQueryFilter(expression);
        }

        public void OnCreating(ModelBuilder modelBuilder, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
        }

        /// <summary>
        /// 构建 u => EF.Property<bool>(u, "IsDeleted") == false 表达式
        /// </summary>
        /// <param name="entityBuilder"></param>
        /// <returns></returns>
        private LambdaExpression BuilderIsDeleteLambdaExpression(EntityTypeBuilder entityBuilder)
        {
            // 获取实体构建器元数据
            var metadata = entityBuilder.Metadata;
            if (metadata.FindProperty(nameof(Entity.IsDeleted)) == null) return default;

            // 创建表达式元素
            var parameter = Expression.Parameter(metadata.ClrType, "u");
            var properyName = Expression.Constant(nameof(Entity.IsDeleted));
            var propertyValue = Expression.Constant(false);

            // 构建表达式 u => EF.Property<bool>(u, "IsDeleted") == false
            var expressionBody = Expression.Equal(Expression.Call(typeof(EF), nameof(EF.Property), new[] { typeof(bool) }, parameter, properyName), propertyValue);
            var expression = Expression.Lambda(expressionBody, parameter);
            return expression;
        }

        #endregion 全局筛选器

        protected override void SaveChangesFailedEvent(DbContextErrorEventData eventData)
        {
            base.SaveChangesFailedEvent(eventData);
        }

        /// <summary>
        /// 重写保存之前事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void SavingChangesEvent(DbContextEventData eventData, InterceptionResult<int> result)
        {
            // 获取当前事件对应上下文
            var dbContext = eventData.Context;
            // 强制重新检查一边实体更改信息
            dbContext.ChangeTracker.DetectChanges();

            //var a = GetSidValue(dbContext, "");
            //var b = GetNameValue(dbContext, "");

            // 通过请求中获取当前操作人
            //var userId = GetValue(dbContext, "Sid");
            //var userName = GetValue(dbContext, "Name");
            var userId = GetSidValue();
            var userName = GetNameValue();

            #region 审计日志

            //{
            //    // 获取所有更改，删除，新增的实体，但排除审计实体（避免死循环）
            //    var entities = dbContext.ChangeTracker.Entries()
            //        .Where(u => u.Entity.GetType() != typeof(AutidLog) && (u.State == EntityState.Modified ||
            //                                                               u.State == EntityState.Deleted ||
            //                                                               u.State == EntityState.Added))
            //        .ToList();
            //    var autidlogs = new List<AutidLog>();

            //    var changecontent = new StringBuilder();
            //    // 获取所有已更改的实体
            //    foreach (var entity in entities)
            //    {
            //        // 获取实体类型
            //        var entityType = entity.Entity.GetType();

            //        // 获取所有实体有效属性，排除 [NotMapper] 属性
            //        var props = entity.OriginalValues.Properties;

            //        // 获取实体当前（现在）的值
            //        var currentValues = entity.CurrentValues;

            //        // 获取数据库中实体的值
            //        var databaseValues = entity.GetDatabaseValues();

            //        var key = props.FirstOrDefault(o => o.IsPrimaryKey())?.Name;

            //        changecontent.Clear();//遍历前清空
            //        // 遍历所有属性
            //        foreach (var prop in props)
            //        {
            //            // 获取属性名
            //            var propName = prop.Name;

            //            // 获取现在的实体值
            //            var newValue = currentValues[propName];

            //            object oldValue = null;
            //            // 如果是新增数据，则 databaseValues 为空，所以需要判断一下
            //            if (databaseValues != null)
            //            {
            //                oldValue = databaseValues[propName];
            //            }
            //            //if (newValue == oldValue) continue;
            //            //if ( newValue.Equals(oldValue)) continue;
            //            if (newValue == oldValue) continue;

            //            changecontent.AppendLine($"{propName}: [{oldValue?.ToString()}] -> [{newValue?.ToString()}]");
            //        }

            //        var autidlog = new AutidLog
            //        {
            //            DataId = key,
            //            Table = entityType.Name, // 表名
            //            //Column = propName, // 更新的列
            //            //NewValue = newValue?.ToString(), // 新值
            //            //OldValue = oldValue?.ToString(), // 旧值
            //            Content = changecontent.ToString(),
            //            CreatedTime = DateTime.Now, // 操作时间
            //            UserId = Convert.ToInt32(userId ?? 0), // 操作人
            //            UserName = userName?.ToString(),
            //            Operate = GetEntityState(entity.State) // 操作方式：新增、更新、删除
            //        };
            //        autidlogs.Add(autidlog);
            //    }
            //    // 插入审计日志表
            //    // dbContext.AutidLogs.AddRange(autidlogs);
            //    eventData.Context.Add(autidlogs);
            //}

            #endregion 审计日志

            #region 创建人、最后操作人

            {
                //// 获取所有新增和更新的实体
                //var entities = dbContext.ChangeTracker.Entries().Where(u => u.State == EntityState.Added || u.State == EntityState.Modified);

                //foreach (var entity in entities)
                //{
                //    switch (entity.State)
                //    {
                //        // 自动设置租户Id
                //        case EntityState.Added:
                //            entity.Property(nameof(CreateEntity.CreatorUserId)).CurrentValue = userId ?? 0;
                //            entity.Property(nameof(CreateEntity.CreatorUserName)).CurrentValue = userName;
                //            entity.Property(nameof(CreateEntity.CreationTime)).CurrentValue = DateTime.Now;
                //            break;
                //        // 排除租户Id
                //        case EntityState.Modified:
                //            entity.Property(nameof(Entity.TenantId)).IsModified = false;

                //            entity.Property(nameof(FullEntity.LastModifierUserId)).CurrentValue = userId ?? 0;
                //            entity.Property(nameof(FullEntity.LastModifierUserName)).CurrentValue = userName;
                //            entity.Property(nameof(FullEntity.LastModificationTime)).CurrentValue = DateTime.Now;

                //            break;
                //    }
                //}

                // 获取所有新增和更新的实体
                var entities = dbContext.ChangeTracker.Entries().Where(u => u.State == EntityState.Added || u.State == EntityState.Modified || u.State == EntityState.Deleted).ToList();
                //子实体被修改的时候，去这里找旧的值，这样就不用去数据库再找一遍了
                //var deletedcache = entities.Where(d => d.State == EntityState.Deleted).ToDictionary(d => d.Entity.GetType().FullName + d.Property("Id").CurrentValue, d => d);
                foreach (var entity in entities)
                {
                    switch (entity.State)
                    {
                        case EntityState.Added:
                            if (entity.Entity is not ICreate creationtimeentity)
                            {
                                continue;
                            }
                            if (creationtimeentity.CreationTime == default)
                            {
                                creationtimeentity.CreationTime = DateTimeOffset.Now;
                            }
                            break;

                        case EntityState.Modified:

                            if (entity.Entity is IDeleted deleted)
                            {
                                var isdeleted = entity.Property(nameof(IDeleted.IsDeleted)).CurrentValue;
                                if ((bool)isdeleted == true)
                                {
                                    if (entity.Entity is IDeleted deletedentity)
                                    {
                                        deletedentity.DeletedTime = DateTimeOffset.Now;
                                        deletedentity.DeletedUserId = Convert.ToInt32(userId ?? 0);
                                        deletedentity.DeletedUserName = userName?.ToString();
                                    }
                                }
                                else
                                {
                                    if (entity.Entity is IUpdate updatetimeentity)
                                    {
                                        updatetimeentity.UpdateTime = DateTimeOffset.Now;
                                        updatetimeentity.UpdateUserId = Convert.ToInt32(userId ?? 0);
                                        updatetimeentity.UpdateUserName = userName?.ToString();
                                    }
                                }
                            }
                            else
                            {
                                if (entity.Entity is IUpdate updatetimeentity)
                                {
                                    updatetimeentity.UpdateTime = DateTimeOffset.Now;
                                    updatetimeentity.UpdateUserId = Convert.ToInt32(userId ?? 0);
                                    updatetimeentity.UpdateUserName = userName?.ToString();
                                }
                            }

                            //if (entity.Entity is ICreate)
                            //{
                            //    var key = entity.Entity.GetType().FullName + entity.Property("Id").CurrentValue;
                            //    if (deletedcache.ContainsKey(key))
                            //    {
                            //        entity.Property(nameof(ICreate.CreationTime)).CurrentValue = deletedcache[key].Property(nameof(ICreate.CreationTime)).CurrentValue;
                            //    }
                            //    else
                            //    {
                            //        entity.Property(nameof(ICreate.CreationTime)).IsModified = false;
                            //    }
                            //}
                            //if (entity.Entity is IUpdate updatetimeentity)
                            //{
                            //    updatetimeentity.LastModificationTime = DateTime.Now;
                            //}
                            break;

                        case EntityState.Deleted:
                            // entity.Property(nameof(FullEntity.DeletionTime)).CurrentValue = DateTime.Now ;

                            break;
                    }
                }
            }

            #endregion 创建人、最后操作人

            base.SavingChangesEvent(eventData, result);
        }

        private object GetValue(string key)
        {
            var httpcontext = App.GetService<IHttpContextAccessor>().HttpContext;
            if (httpcontext == null)
            {
                return default;
            }
            return httpcontext?.User?.FindFirst(key)?.Value ?? "";
        }

        private object GetSidValue()
        {
            var v = "0";
            try
            {
                var httpcontext = App.GetService<IHttpContextAccessor>().HttpContext;
                v = httpcontext?.User?.FindFirst(ClaimTypes.Sid)?.Value ?? "0";
            }
            catch (Exception e)
            {
            }
            return v;
            ;
        }

        private object GetNameValue()
        {
            var v = "";
            try
            {
                var httpcontext = App.GetService<IHttpContextAccessor>().HttpContext;
                if (httpcontext == null)
                {
                    return default;
                }
                v = httpcontext?.User?.Identity?.Name;
            }
            catch (Exception e)
            {
            }
            return v;
        }

        /// <summary>
        /// 获取实体更改状态 中文状态
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public string GetEntityState(EntityState state)
        {
            switch (state)
            {
                case EntityState.Added:
                    return "新增";

                case EntityState.Deleted:
                    return "删除";

                case EntityState.Detached:
                    return "未跟踪";

                case EntityState.Modified:
                    return "更新";

                case EntityState.Unchanged:
                    return "未改变";

                default:
                    return state.ToString("G");
            }
        }
    }
}